import React from 'react';
import './App.css';
import { PBTerninalConfigration, PBDeviceInfo, PBNetInfo, PBServerInfo } from './config';
import protobufjs from 'protobufjs';
import { ValidationInput } from './ValidationInput';
import { int_to_bytes, bytes_to_hex, check_is_valid_ip_str, ip_to_int } from './utils';

interface AppState {
  config: PBTerninalConfigration;
}

class App extends React.Component<{}, AppState>{
  constructor(props: any) {
    super(props);
    this.state = {
      config: PBTerninalConfigration.create({
        deviceInfo: PBDeviceInfo.create({
          terminalSn: '123456',
          logLevel: 1,
        }),
        netInfo: PBNetInfo.create({
          macAddr: new Uint8Array([0xff, 0x01, 0x02, 0x03, 0x04, 0x05]),
          ip: new DataView(new Uint8Array([192, 168, 1, 2]).buffer).getUint32(0, false),
          subnetMask: new DataView(new Uint8Array([255, 255, 255, 0]).buffer).getUint32(0, false),
          gateway: new DataView(new Uint8Array([192, 168, 1, 1]).buffer).getUint32(0, false),
          dns: new DataView(new Uint8Array([8, 8, 8, 8]).buffer).getUint32(0, false),
          useDhcp: true,
        }),
        serverInfo: PBServerInfo.create({
          hostname: 'baidu.com',
          port: 8080
        }),
      }),
    };
  }

  render() {
    return (
      <div className="App flex flex-col justify-center items-center">
        <h1 className="text-3xl p-4">Porotocol Buffers Typescript</h1>

        <table className='border table-fixed w-2/3'>
          <tbody>
            <tr >
              <td>终端序列号</td>
              <td>
                <ValidationInput
                  defaultValue={this.state.config.deviceInfo?.terminalSn}
                  onValidChange={(val) => {
                    this.setState({
                      config: {
                        ...this.state.config, deviceInfo: PBDeviceInfo.create({
                          ...this.state.config.deviceInfo,
                          terminalSn: val.target.value
                        })
                      }
                    });
                  }}
                  validation={/^\d+$/} >
                </ValidationInput>
              </td>
            </tr>
            <tr className='border-b'>
              <td>日志级别</td>
              <td>
                <ValidationInput
                  defaultValue={this.state.config.deviceInfo?.logLevel.toString()}
                  onValidChange={(val) => {
                    console.error(val.target.value);
                    this.setState({
                      config: {
                        ...this.state.config, deviceInfo: PBDeviceInfo.create({
                          ...this.state.config.deviceInfo,
                          logLevel: parseInt(val.target.value)
                        })
                      }
                    });
                  }}
                  validation={/^\d{1}$/} >
                </ValidationInput>
              </td>
            </tr>
            <tr>
              <td>mac地址</td>
              <td>
                <ValidationInput
                  defaultValue={() => {
                    let hex_str: String[] = [];
                    this.state.config.netInfo?.macAddr.forEach((val) => {
                      let byte = val.toString(16).toUpperCase();
                      byte = byte.length === 1 ? '0' + byte : byte
                      hex_str.push(byte)
                    });
                    return hex_str.join(':');
                  }}
                  onValidChange={(val) => {
                    let bytes_array: number[] = [];
                    val.target.value.split(':').forEach((val) => { bytes_array.push(parseInt(val, 16)) })
                    this.setState({
                      config: {
                        ...this.state.config, netInfo: PBNetInfo.create({
                          ...this.state.config.netInfo,
                          macAddr: new Uint8Array(bytes_array)
                        })
                      }
                    });
                  }}
                  validation={/^([\da-f]{2}\:){5}[\da-f]{2}$/i} >
                </ValidationInput>
              </td>
            </tr>
            <tr>
              <td>是否使用dhcp</td>
              <td>
                <ValidationInput
                  defaultValue={this.state.config.netInfo?.useDhcp.toString()}
                  onValidChange={(val) => {
                    let bytes_array: number[] = [];
                    val.target.value.split(':').forEach((val) => { bytes_array.push(parseInt(val, 16)) })
                    this.setState({
                      config: {
                        ...this.state.config, netInfo: PBNetInfo.create({
                          ...this.state.config.netInfo,
                          useDhcp: val.target.value.toLowerCase() === 'true' ? true : false
                        })
                      }
                    });
                  }}
                  validation={/^(true|false)$/i} >
                </ValidationInput>
              </td>
            </tr>
            <tr>
              <td>ip地址</td>
              <td>
                <ValidationInput
                  defaultValue={int_to_bytes(this.state.config.netInfo?.ip)?.join('.')}
                  onValidChange={(val) => {
                    this.setState({
                      config: {
                        ...this.state.config, netInfo: PBNetInfo.create({
                          ...this.state.config.netInfo,
                          ip: ip_to_int(val.target.value)
                        })
                      }
                    });
                  }}
                  validation={check_is_valid_ip_str} >
                </ValidationInput>
              </td>
            </tr>
            <tr>
              <td>网关地址</td>
              <td>
                <ValidationInput
                  defaultValue={int_to_bytes(this.state.config.netInfo?.gateway)?.join('.')}
                  onValidChange={(val) => {
                    this.setState({
                      config: {
                        ...this.state.config, netInfo: PBNetInfo.create({
                          ...this.state.config.netInfo,
                          gateway: ip_to_int(val.target.value)
                        })
                      }
                    });
                  }}
                  validation={check_is_valid_ip_str} >
                </ValidationInput>
              </td>
            </tr>
            <tr>
              <td>子网掩码</td>
              <td>
                <ValidationInput
                  defaultValue={int_to_bytes(this.state.config.netInfo?.subnetMask)?.join('.')}
                  onValidChange={(val) => {
                    this.setState({
                      config: {
                        ...this.state.config, netInfo: PBNetInfo.create({
                          ...this.state.config.netInfo,
                          subnetMask: ip_to_int(val.target.value)
                        })
                      }
                    });
                  }}
                  validation={check_is_valid_ip_str} >
                </ValidationInput>
              </td>
            </tr>
            <tr className='border-b'>
              <td>dns地址</td>
              <td>
                <ValidationInput
                  defaultValue={int_to_bytes(this.state.config.netInfo?.dns)?.join('.')}
                  onValidChange={(val) => {
                    this.setState({
                      config: {
                        ...this.state.config, netInfo: PBNetInfo.create({
                          ...this.state.config.netInfo,
                          dns: ip_to_int(val.target.value)
                        })
                      }
                    });
                  }}
                  validation={check_is_valid_ip_str} >
                </ValidationInput>
              </td>
            </tr>
            <tr >
              <td>服务器主机名</td>
              <td>
                <ValidationInput
                  defaultValue={this.state.config.serverInfo?.hostname}
                  onValidChange={(val) => {
                    this.setState({
                      config: {
                        ...this.state.config, serverInfo: PBServerInfo.create({
                          ...this.state.config.serverInfo,
                          hostname: val.target.value
                        })
                      }
                    });
                  }}
                  validation={(text) => /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/.test(text) || check_is_valid_ip_str(text)} >
                </ValidationInput>
              </td>
            </tr>
            <tr className='border-b'>
              <td>端口号</td>
              <td>
                <ValidationInput
                  defaultValue={this.state.config.serverInfo?.port.toString()}
                  onValidChange={(val) => {
                    this.setState({
                      config: {
                        ...this.state.config, serverInfo: PBServerInfo.create({
                          ...this.state.config.serverInfo,
                          port: parseInt(val.target.value)
                        })
                      }
                    });
                  }}
                  validation={(text) => /^[\d]+$/.test(text) && parseInt(text) < 65535} >
                </ValidationInput>
              </td>
            </tr>

            <tr className='border-b text-left'>
              <td className='border-r'>
                <pre className='text-[#5AB500]'>
                  /* 原始数据 */
                </pre>
                <pre>
                  {((): String => {
                    return JSON.stringify(PBTerninalConfigration.toJSON(this.state.config), null, 4);
                  })()}
                </pre>
              </td>
              <td>
                <pre className='text-[#5AB500]'>
                  /* 反序列化后 */
                </pre>
                <pre>
                  {((): String => {
                    /* 反序列化 */
                    let writer = protobufjs.Writer.create();
                    PBTerninalConfigration.encode(this.state.config, writer);
                    let bytes = writer.finish();
                    let reader = protobufjs.Reader.create(bytes);
                    let unmarshal_config = PBTerninalConfigration.decode(reader);
                    return JSON.stringify(PBTerninalConfigration.toJSON(unmarshal_config), null, 4);
                  })()}
                </pre>
              </td>
            </tr>
            <tr className='border-b text-left'>
              <td colSpan={2}>
                <p className=''>
                  {((): String => {
                    let writer = protobufjs.Writer.create();
                    PBTerninalConfigration.encode(this.state.config, writer);
                    return bytes_to_hex(writer.finish()).toString();
                  })()}
                </p>
              </td>
            </tr>
          </tbody>
        </table>
      </div >
    );
  }
}

export default App;
